import { Injectable, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../prisma/prisma.service';
import * as fs from 'fs';
import * as path from 'path';

@Injectable()
export class UploadService {
  constructor(
    private configService: ConfigService,
    private prisma: PrismaService,
  ) {}

  async uploadFile(
    file: Express.Multer.File,
    userId: number,
    originalname?: string,
  ) {
    if (!file) {
      throw new BadRequestException('没有文件上传');
    }

    const uploadPath = this.configService.get('upload.path') || './uploads';
    const maxFileSize =
      this.configService.get('upload.maxFileSize') || 10485760; // 10MB

    // 检查文件大小
    if (file.size > maxFileSize) {
      throw new BadRequestException('文件大小超过限制');
    }

    // 确保上传目录存在
    if (!fs.existsSync(uploadPath)) {
      fs.mkdirSync(uploadPath, { recursive: true });
    }

    // 生成唯一文件名
    const timestamp = Date.now();
    const randomString = Math.random().toString(36).substring(2, 15);
    originalname = originalname || file.originalname;
    const extension = path.extname(originalname);
    const fileName = `${timestamp}_${randomString}${extension}`;
    const filePath = path.join(uploadPath, fileName);

    // 保存文件
    fs.writeFileSync(filePath, file.buffer);

    // 确定文件类型
    const fileType = this.getFileType(file.mimetype, extension);

    // 保存文件记录到数据库
    const fileRecord = await this.prisma.file.create({
      data: {
        name: originalname,
        path: fileName,
        type: fileType,
        size: file.size,
        mimeType: file.mimetype,
        uploadedById: userId,
      },
    });

    return {
      id: fileRecord.id,
      name: fileRecord.name,
      type: fileRecord.type,
      size: fileRecord.size,
      url: `/uploads/${fileName}`,
    };
  }

  async getFile(fileId: number, userId: number) {
    const file = await this.prisma.file.findUnique({
      where: { id: fileId },
      include: {
        uploadedBy: {
          select: {
            id: true,
            username: true,
          },
        },
      },
    });

    if (!file) {
      throw new BadRequestException('文件不存在');
    }

    // 检查权限：上传者或公开文件
    if (file.uploadedById !== userId && !file.isPublic) {
      throw new BadRequestException('没有权限访问此文件');
    }

    const uploadPath = this.configService.get('upload.path') || './uploads';
    const filePath = path.join(uploadPath, file.path);

    if (!fs.existsSync(filePath)) {
      throw new BadRequestException('文件不存在');
    }

    return {
      file,
      filePath,
    };
  }

  async getFileByFilename(filename: string) {
    const file = await this.prisma.file.findFirst({
      where: { path: filename },
      include: {
        uploadedBy: {
          select: {
            id: true,
            username: true,
          },
        },
      },
    });

    if (!file) {
      throw new BadRequestException('文件不存在');
    }

    const uploadPath = this.configService.get('upload.path') || './uploads';
    const filePath = path.join(uploadPath, file.path);

    if (!fs.existsSync(filePath)) {
      throw new BadRequestException('文件不存在');
    }

    return {
      file,
      filePath,
    };
  }

  async deleteFile(fileId: number, userId: number) {
    const file = await this.prisma.file.findUnique({
      where: { id: fileId },
    });

    if (!file) {
      throw new BadRequestException('文件不存在');
    }

    // 检查权限：只有上传者可以删除
    if (file.uploadedById !== userId) {
      throw new BadRequestException('没有权限删除此文件');
    }

    // 删除物理文件
    const uploadPath = this.configService.get('upload.path') || './uploads';
    const filePath = path.join(uploadPath, file.path);

    if (fs.existsSync(filePath)) {
      fs.unlinkSync(filePath);
    }

    // 删除数据库记录
    await this.prisma.file.delete({
      where: { id: fileId },
    });

    return { message: '文件已删除' };
  }

  private getFileType(mimeType: string, extension: string): string {
    const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    const videoTypes = ['video/mp4', 'video/avi', 'video/mov', 'video/wmv'];
    const audioTypes = ['audio/mp3', 'audio/wav', 'audio/ogg', 'audio/m4a'];

    if (
      imageTypes.includes(mimeType) ||
      ['.jpg', '.jpeg', '.png', '.gif', '.webp'].includes(
        extension.toLowerCase(),
      )
    ) {
      return 'image';
    }

    if (
      videoTypes.includes(mimeType) ||
      ['.mp4', '.avi', '.mov', '.wmv'].includes(extension.toLowerCase())
    ) {
      return 'video';
    }

    if (
      audioTypes.includes(mimeType) ||
      ['.mp3', '.wav', '.ogg', '.m4a'].includes(extension.toLowerCase())
    ) {
      return 'audio';
    }

    return 'file';
  }
}
